fix(desktop): seed nest Claude settings with buzz CLI allowlist - #5263
fix(desktop): seed nest Claude settings with buzz CLI allowlist#5263thomaspblock wants to merge 2 commits into
Conversation
Since #4609 the ACP harness rejects every session/request_permission (fail closed) and desktop managed sessions run in dontAsk mode with no in-app approval prompt. Claude Code raises a permission request for any Bash pattern not pre-authorized in its settings, so managed Claude agents lost all access to the bundled `buzz` CLI — they could not read channels or send replies (#5262, #5260). Claude Code evaluates permissions.allow rules before the permission mode, so a project-level allow rule survives dontAsk. Seed `<nest>/.claude/settings.json` with `Bash(buzz)` and `Bash(buzz:*)` at nest creation: managed sessions start with the nest root as cwd and the ACP adapter passes settingSources ["user", "project", "local"], so the rules apply to every managed Claude agent without touching the user's own ~/.claude/settings.json. The merge is conservative: existing settings are preserved, only missing rules are appended, unparseable or unexpectedly-shaped files are left untouched, and the write is atomic (temp file + persist, matching refresh_skill_md_if_stale). Idempotent across launches. This deliberately does not reopen the blanket auto-approval that #4609 removed: only the platform's own CLI is pre-authorized, agent-side, which #4609 explicitly scopes as outside the harness guarantee. The broader fix (harness permission policy with desktop approval cards) is in flight as #5106; this unblocks agents until it lands. Known limitation: allow rules match single commands only — `buzz feed get` runs, but `buzz ... | head` or `buzz ...; echo $?` still raises a request and is rejected under dontAsk. Fixes #5262. Co-authored-by: Thomas Petersen <thomasp@squareup.com> Signed-off-by: Thomas Petersen <thomasp@squareup.com>
|
yea need this one in asap boys |
Yeah, spent about 90 minutes on this one today until narrowed it down to the conflicting startup and config. Anyways, reported, and being handled it appears. |
|
I tested this patch strategy against Claude Code 2.1.220 on Buzz Desktop 0.5.6, macOS, with a locally managed agent connected to a self-hosted relay. The proposed The fresh headless Claude process emitted: This matches the current Claude Code workspace-trust behavior: project I then moved the exact same rules: {
"permissions": {
"allow": [
"Bash(buzz)",
"Bash(buzz:*)"
]
}
}to Recommendation: seed and conservatively merge I posted the full reproduction on #5262 as well. |
wolfyy970
left a comment
There was a problem hiding this comment.
I agree that managed agents need a reliable Buzz reply path, but this head does not provide it yet.
Current Claude ignores .claude/settings.json allow rules in a fresh untrusted workspace. The field reproduction on this PR confirms it. The acceptance test needs to launch current Claude from a fresh nest under dontAsk and prove both buzz --help and a signed buzz messages send work without a trust dialog.
I would also avoid leaving Bash(buzz:*) as an unowned permanent workspace grant. It covers every Buzz CLI operation, applies to every managed Claude agent sharing the nest, and is never removed or reconciled. Once active, it can make a later Reject choice in #5106 misleading because Claude will approve the command before ACP asks Buzz.
The clean boundary is a session-scoped, target-owned platform allowance. If settings.local.json is needed for the emergency fix, that is still better than shipping a non-working patch, but Buzz should mark and reconcile what it owns, refuse a symlinked settings directory, and define the cleanup path before #5106 lands.
wesbillman
left a comment
There was a problem hiding this comment.
Carl reviewing on Wes's behalf.
This does not restore the managed-Claude reply path on the current runtime. Claude Code ignores capability-granting rules from project .claude/settings.json until that workspace is trusted; a fresh Buzz nest never receives the interactive trust acceptance. The independent reproductions on this PR and #5262 show the exact headless warning and denial, while the same rules in .claude/settings.local.json work under dontAsk without a trust dialog.
Please target the headless-safe local settings source (or another mechanism proven to work in an untrusted nest) and add an acceptance test that launches the current Claude runtime from a fresh nest and proves both buzz --help and a signed buzz messages send complete without a permission request. The five new tests only verify JSON merging, so they remain green while the shipped behavior is inert.
Before writing the settings file, also reject a symlinked .claude directory/settings path. ensure_nest_at protects only the root; this new create_dir_all/read/tempfile/persist sequence otherwise follows an existing .claude directory symlink and writes outside the Buzz-owned nest.
wesbillman
left a comment
There was a problem hiding this comment.
Two blocking findings at 724fed49d9c303f59820c5ddfc527307490a1526:
-
The seeded file is ignored in the exact fresh/headless case this PR needs to repair. Current Claude Code gates project
permissions.allowfrom.claude/settings.jsonon workspace trust. A fresh Buzz nest has not accepted that interactive trust dialog, so Claude logsIgnoring 2 permissions.allow entries ... workspace has not been trustedand continues denyingbuzzunderdontAsk. This has now been reproduced against Claude Code 2.1.220 and independently with 2.1.226; moving the same rules to.claude/settings.local.jsonworked without marking the workspace trusted. The five tests only prove JSON merging—they never launch Claude—so they cannot establish the claimed fix. Please target a source that current headless Claude actually honors and add an acceptance test using a fresh, untrusted nest underdontAsk, proving at minimum a bare command and a signedbuzz messages sendexecute without a trust dialog. -
The grant has no ownership or lifecycle boundary.
ensure_nest_atappendsBash(buzz:*)on every launch and never records whether Buzz inserted it, removes it, or reconciles it when #5106 supplies first-class approvals. It applies to every Claude session using this shared nest, not just the managed session being repaired. Once honored, Claude approves the command before ACP asks Buzz, so a later user-facing Reject decision can be bypassed by this stale workspace rule. Please make the emergency grant explicitly Buzz-owned/reconcilable (and define cleanup during the #5106 transition), or preferably scope the permission at the managed session/target boundary.
Related hardening: refuse a symlinked .claude directory before creating or rewriting settings. The nest root check does not protect this child path, and create_dir_all/read_to_string/persist will follow a directory symlink outside the Buzz nest.
The outage is real and urgent, but this head is not the fix: it silently leaves fresh managed Claude agents unable to publish while installing a permanent grant that may become active later. Green Rust tests do not cover that runtime contract.
Write the managed nest allowlist to Claude's local settings source, which remains active before a fresh headless workspace is trusted. Refuse symlinked Claude settings paths so the seed cannot escape the nest. Co-authored-by: Carl <c7ebe626f000404285d3686e1dc74cc07cc60a9754a150041ba132e14bd3e2ec@buzz.block.builderlab.xyz> Signed-off-by: Wes <wesbillman@users.noreply.github.com>
|
Maintainer takeover is pushed at exact head This addresses my previous changes-requested review:
Runtime evidence: {"accepted":true,"event_id":"121c1936e1aa50740900322d1b9f9a460295068268454678df0ff8fa4ef31d38","mention_pubkeys":[],"message":""}Adapter stderr was empty and the fail-closed ACP probe received no permission request. Pre-push passed the repo's broad Rust/Desktop suite on this exact head. Commenting and implementing on Wes's behalf. |
wesbillman
left a comment
There was a problem hiding this comment.
Re-reviewed exact head 91838616a99e8941b9fb47ce910e6dc45052ad9d. My prior blockers are resolved; I found no new actionable correctness or security issue.
- The grant now targets
.claude/settings.local.json, while a regression test proves projectsettings.jsonis untouched. - Existing model/allow/deny/unknown data remains conservatively merged; invalid and unexpected shapes remain untouched; writes stay idempotent and atomic.
- Both descendant symlink cases are rejected and tested, including proof that external targets are unchanged.
- The code and PR explicitly identify this as temporary Buzz-owned compatibility behavior with cleanup/reconciliation tied to #5106.
- Most importantly, the exact head was exercised through
@zed-industries/claude-agent-acpunderdontAskfrom a fresh untrusted nest with pre-existing local settings:buzz --helpsucceeded and a signed send returnedaccepted:true, with no permission request or adapter stderr. That closes the runtime-proof gap that invalidated the original head.
git diff --check is clean. I am leaving a comment verdict rather than auto-approving under the repository's approval policy. From substantive review, this is release-ready once required CI completes green without another head change.
Approval withdrawn at Wes Billman’s request pending further review.
Fixes #5262. Related: #5260 (same root cause, independently reported twice today).
Problem
Since #4609 the ACP harness rejects every
session/request_permission(fail closed), and Desktop-managed sessions run indontAskmode with no in-app approval prompt. Claude Code raises a permission request for any Bash pattern not pre-authorized in its settings, so managed Claude agents lost access to the bundledbuzzCLI: they appear online but cannot reliably read channels or send replies.Fix
Seed and conservatively merge
<nest>/.claude/settings.local.jsonwithBash(buzz)andBash(buzz:*)duringensure_nest_at..claude/settings.jsongrants are ignored until interactive workspace trust is accepted..claudedirectories and settings files are rejected before read/write, and regression tests prove external targets remain unchanged.~/.claudeconfiguration is never touched.This is temporary Buzz-owned compatibility behavior. It restores Buzz read/reply only; it does not restore broader unattended shell/tool capability. Reconcile or remove this workspace grant when Desktop permission approval UI ships in #5106.
Known limitation
Allow rules match single commands only:
buzz feed getruns, butbuzz ... | headorbuzz ...; echo $?still raises a request and is rejected underdontAsk.Testing
Exact pushed head:
91838616a99e8941b9fb47ce910e6dc45052ad9dclaude_settingstests passed (5 original merge tests plus project-settings-untouched and both symlink escape cases).settings.local.jsonincluded unrelated model/allow/deny values. Through the actualclaude-agent-acpACP path, the session mode was set todontAskand permission requests were fail-closed, matching the managed harness contract.@zed-industries/claude-agent-acp0.18.0buzz --help: succeeded (Usage: buzz [OPTIONS] <COMMAND>)buzz messages send:{"accepted":true,"event_id":"121c1936e1aa50740900322d1b9f9a460295068268454678df0ff8fa4ef31d38","mention_pubkeys":[],"message":""}